
package bibp2pdesk;


import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.logging.Level;
import java.util.logging.Logger;
import rice.tutorial.past.PastAdmin;

/**
 *
 * @author lauro
 */
public class P2PFile {

    public P2PFile(File fp) {
        this.file = fp;
        this.md5sum = new byte[16];
        this.blockSize = 256 * 1024;


        int r;
        byte[] buffer = new byte[8 * 1024];
        InputStream is = null;


        try {
            is = new FileInputStream(this.file);
        } catch (FileNotFoundException ex) {
            Logger.getLogger(P2PFile.class.getName()).log(Level.SEVERE, null, ex);
        }


        try {
            this.md5 = MessageDigest.getInstance("MD5");
            try {
                while ((r = is.read(buffer)) > 0) {
                    this.md5.update(buffer, 0, r);
                }
            } catch (IOException ex) {
                Logger.getLogger(P2PFile.class.getName()).log(Level.SEVERE, null, ex);
            }

            this.md5sum = this.md5.digest();
            BigInteger bigInt = new BigInteger(1, this.md5sum);
            this.key = bigInt.toString(16);
            while (this.key.length() < 32) {
                this.key = "0" + this.key;
        }

        } catch (NoSuchAlgorithmException ex) {
            Logger.getLogger(P2PFile.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    public P2PFile(String key) {
        this.key = key;
        this.md5sum = key.getBytes();
        this.file = null;
        this.blockSize = 256 * 1024;
        
    }

    public String getFilePath() {
        if(this.file == null)
            return null;
        return this.file.getAbsolutePath();
    }

    public String getFileKey() {
        return this.key;
    }

    public long getFileSize() {
        return this.file.length();
    }

    public int getBlockCount() {
        int b = (int) (this.file.length() / this.blockSize);
        if(this.file.length() % this.blockSize > 0)
            b++;
        return b;
    }


    public void insertFile(PastAdmin past) throws Exception {
        byte[] block = new byte[this.blockSize];
        String blockKey = null;
        InputStream is = null;
        int i = 0;
        int r = 0;

        try {
            is = new FileInputStream(this.file);
        } catch (FileNotFoundException ex) {
            Logger.getLogger(P2PFile.class.getName()).log(Level.SEVERE, null, ex);
        }

        
        try {
            //lendo arquivo
            while((r = is.read(block)) > 0) {
                blockKey = this.getBlockKey(i++);
                //TRANSFERIR O BLOCO
                if(!past.EnviaArquivo(block , blockKey)) {
                
                    throw new Exception ("Store Fail");
                }
            }
        } catch (IOException ex) {
            Logger.getLogger(P2PFile.class.getName()).log(Level.SEVERE, null, ex);
        }

    }

    public void retrieveFile(String dst, PastAdmin past, int size) throws Exception {
        byte[] block = null;
        OutputStream os = null;
        String blockKey = null;
        int i = 0;
        int r = 0;
        int s = 0;



        try {
            os = new FileOutputStream(dst);
        } catch (FileNotFoundException ex) {
            Logger.getLogger(P2PFile.class.getName()).log(Level.SEVERE, null, ex);
        }

        try {

            do {
                blockKey = this.getBlockKey(i++);
                
                //receber bloco
                block = past.BuscaArquivo(blockKey);
                if(this.blockSize + s > size)
                    r = size - s;
                else
                    r = this.blockSize;

                os.write(block, 0, r);
                s += r;

            } while(s < size);

        } catch (IOException ex) {
            Logger.getLogger(P2PFile.class.getName()).log(Level.SEVERE, null, ex);
        }




    }

    private String getBlockKey(int b) {
//        byte[] blockMd5sum = new byte[16];
//        String blockId;
//        String blockKey = null;
//
//        try {
//            this.md5 = MessageDigest.getInstance("MD5"); //preciso de uma nova instancia??
//
//            blockId = this.key + ":block:" + Integer.toString(b);
//            this.md5.update(blockId.getBytes());
//            blockMd5sum = this.md5.digest();
//            BigInteger bigInt = new BigInteger(1, blockMd5sum);
//            blockKey = bigInt.toString(16);
//            while (blockKey.length() < 32)
//                blockKey = "0" + this.key;
//
//        } catch (NoSuchAlgorithmException ex) {
//            Logger.getLogger(P2PFile.class.getName()).log(Level.SEVERE, null, ex);
//        }

        return this.key + ":block:" + Integer.toString(b);
    }




    private File file;
    private String key;
    private int blockSize;
    private byte[] md5sum;
    private MessageDigest md5;

}
